/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "../../User/Driver/Flash/flash_driver.h"
#include "../../User/BSP/SDIO_BSP/sdio_sd_bsp.h"

/*每个驱动器的物理驱动器号定义 */
#define DEV_RAM		0	/* 示例：将虚拟RAM映射到物理驱动器0 */
#define DEV_MMC		1	/* 示例：将MMC/SD卡映射到物理驱动器1 */
#define DEV_USB		2	/* 示例：将USB映射到物理驱动器2 */
#define DEV_FLASH	3	/* 示例：将Flash映射到物理驱动器3 */

#define SD_Block_Size   512

extern SD_CardInfo SDCardInfo;


/*-----------------------------------------------------------------------*/
/* 获取驱动器状态                                                         */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
	int result;

	switch (pdrv)
	{
	case DEV_RAM :
		////result = RAM_disk_status();
		// translate the reslut code here
		return stat;
	case DEV_MMC :
		return RES_OK;
	case DEV_USB :
		////result = USB_disk_status();
		// translate the reslut code here
		return stat;
	case DEV_FLASH :
		result = WHT_Flash_Driver.Flash_disk_status();
		printf("disk_status: %s\r\n", result == 0 ? "RES_OK" : "STA_NOINIT");
		return result == 0 ? RES_OK : STA_NOINIT;
	}
	return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/*  初始化驱动器                                                          */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
	int result;
	
	switch (pdrv)
	{
	case DEV_RAM :
		////result = RAM_disk_initialize();
		// translate the reslut code here
		return stat;
	case DEV_MMC :
		result = SD_Init();
		return result == SD_OK ? RES_OK : STA_NOINIT;
	case DEV_USB :
		////result = USB_disk_initialize();
		// translate the reslut code here
		return stat;
	case DEV_FLASH :
		result = WHT_Flash_Driver.Flash_disk_initialize();
		printf("flash ID =0x%x\r\n", WHT_Flash_Driver.WHT_Info->ID);
		return result == 0 ? RES_OK : STA_NOINIT;
	}
	return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* 读取扇区，扇区最小单位即4096字节                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
	BYTE *buff,		/* Data buffer to store read data */
	LBA_t sector,	/* Start sector in LBA */
	UINT count		/* Number of sectors to read */
)
{
	DRESULT res;
	int result;

	switch (pdrv)
	{
	case DEV_RAM :
		// translate the arguments here
		////result = RAM_disk_read(buff, sector, count);
		// translate the reslut code here
		return res;
	case DEV_MMC :
		if ((LBA_t)buff & 3)
		{
			LBA_t Scratch[SD_Block_Size/4];

			while (count--)
			{
				res = disk_read(DEV_MMC, (BYTE*)Scratch, sector++, 1);
				if (res != RES_OK)
				{
					break;
				}
				memcpy(buff, Scratch, SD_Block_Size);
				buff += SD_Block_Size;
			}
			return res;
		}
		result = SD_ReadMultiBlocks(buff, sector * SD_Block_Size, SD_Block_Size, count);
		if (result == SD_OK)
		{
			/* Check if the Transfer is finished */
			result = SD_WaitReadOperation();
			while(SD_GetStatus() != SD_TRANSFER_OK);
		}
		return result == SD_OK ? RES_OK : RES_PARERR;
	case DEV_USB :
		// translate the arguments here
		////result = USB_disk_read(buff, sector, count);
		// translate the reslut code here
		return res;
	case DEV_FLASH :
		printf("[disk_read]: sector=%d, count=%d\r\n", sector, count);
		WHT_Flash_Driver.Flash_disk_read(buff, sector, count);
		return RES_OK;
	}
	return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* 写入扇区，扇区最小单位即4096字节                                        */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	LBA_t sector,		/* Start sector in LBA */
	UINT count			/* Number of sectors to write */
)
{
	DRESULT res;
	int result;

	switch (pdrv)
	{
	case DEV_RAM :
		// translate the arguments here
		////result = RAM_disk_write(buff, sector, count);
		// translate the reslut code here
		return res;
	case DEV_MMC :
		if ((LBA_t)buff & 3)
		{
			LBA_t Scratch[SD_Block_Size/4];

			while (count--)
			{
				memcpy(Scratch, buff, SD_Block_Size);
				res = disk_write(DEV_MMC, (BYTE*)Scratch, sector++, 1);
				if (res != RES_OK)
				{
					break;
				}
				buff += SD_Block_Size;
			}
			return res;
		}
		result = SD_WriteMultiBlocks((uint8_t*)buff, sector * SD_Block_Size, SD_Block_Size, count);
		if (result == SD_OK)
		{
			/* Check if the Transfer is finished */
			result = SD_WaitWriteOperation();
			/* Wait until end of DMA transfer */
			while(SD_GetStatus() != SD_TRANSFER_OK);
		}
		return result == SD_OK ? RES_OK : RES_PARERR;
	case DEV_USB :
		// translate the arguments here
		////result = USB_disk_write(buff, sector, count);
		// translate the reslut code here
		return res;
	case DEV_FLASH :
		printf("[disk_write]: sector=%d, count=%d\r\n", sector, count);
		WHT_Flash_Driver.Flash_disk_write(buff, sector, count);
		return RES_OK;
	}
	return RES_PARERR;
}

#endif


/*-----------------------------------------------------------------------*/
/* 其它控制                                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;
	int result;

	switch (pdrv)
	{
	case DEV_RAM :
		// Process of the command for the RAM drive
		return res;
	case DEV_MMC :
		switch (cmd)
		{
		case GET_SECTOR_COUNT:
			*(LBA_t*)buff = SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize;;
			break;
		case GET_SECTOR_SIZE:
			*(LBA_t*)buff = SD_Block_Size;
			break;
		case GET_BLOCK_SIZE:
			*(LBA_t*)buff = 1;
			break;
		case CTRL_SYNC:
			break;
		default:
			return RES_PARERR;;
		}
		return RES_OK;
	case DEV_USB :
		// Process of the command the USB drive
		return res;
	case DEV_FLASH :
		switch (cmd)
		{
		case GET_SECTOR_COUNT:/* 扇区数量：128个块*16个扇区=2048个扇区) */
			*(LBA_t*)buff = WHT_Flash_Driver.WHT_Info->Sector_Count;
			break;
		case GET_SECTOR_SIZE:/*一个扇区大小*/
			*(LBA_t*)buff = WHT_Flash_Driver.WHT_Info->Sector_Size;
			break;
		case GET_BLOCK_SIZE:/*每次擦除扇区个数*/
			*(LBA_t*)buff = 1;
			break;
		default:
			return RES_PARERR;
		}
		return RES_OK;
	}
	return RES_PARERR;
}

